home *** CD-ROM | disk | FTP | other *** search
- RCS_ID_C="$Id: nio.c,v 3.5 1994/05/14 12:39:24 ppessi Exp $";
- /*
- * nio.c - Generalized I/O (input from almost anywhere!)
- *
- * Author: ppessi <Pekka.Pessi@hut.fi>
- *
- * Copyright (c) 1993 Pekka Pessi
- *
- * Created : Sun Nov 7 07:45:34 1993 ppessi
- * Last modified: Sat May 14 15:38:31 1994 ppessi
- *
- * $Log: nio.c,v $
- * Revision 3.5 1994/05/14 12:39:24 ppessi
- * Added support for telnet. Fixed a couple of bugs in rlogin code.
- *
- * Revision 3.4 1994/02/25 16:08:03 ppessi
- * Added the usergroup.library usage
- *
- * Revision 3.3 1994/02/25 02:04:12 ppessi
- * Changed slightly the const defintions for np.title
- *
- * Revision 3.2 1994/01/08 08:56:33 ppessi
- * Removed <stdio.h> from includes
- *
- * Revision 3.1 94/01/07 22:51:41 ppessi
- * Version 3 beta
- *
- * Revision 2.0 93/11/15 03:42:39 ppessi
- * Version 2 initial revision
- *
- */
-
- #include "amiga.h"
- #include "napsaprefs.h"
- #include "nio.h"
- #include "display.h"
- #include <stdlib.h>
-
- #if USE_SERIAL || USE_STDIO
- struct MsgPort *iop = NULL;
- #endif
- #if USE_SERIAL || USE_STDIO || USE_RLOGIN
- #define INBUFSIZE 512
- char inbuf[INBUFSIZE];
- #endif
- char iobuf[BUFSIZE];
-
- int errno;
-
- /*
- * Generic functions
- */
- long nopen_generic(char **hostvector) { return 0L; }
- long nnread_generic(char *buf, long length) { return -1; }
- long nwrite_generic(char *buf, long length) { return -1; }
- void niosize_generic(ushort s, ushort t, ushort u, ushort v) { }
- void nioctl_generic(int code, int arg1, int arg2) { }
- void nclose_generic(void) { }
- int nabort_generic(void) { return 0; }
-
- /*
- * This is a 'virtual function table' for nio
- */
- struct niotable {
- /* Open nio stream */
- long (*nopen)(char **hostvector);
- /* Read from nio stream */
- long (*nnread)(char *buf, long length);
- /* Write to nio stream */
- long (*nwrite)(char *buf, long length);
- /* Set window size */
- void (*niosize)(ushort, ushort, ushort, ushort);
- /* Send IOCTL command */
- void (*nioctl)(int code, int arg1, int arg2);
- /* Close nio stream */
- void (*nclose)(void);
- /* Abort IO or Resume to IO temporarily */
- int (*nabort)(void);
- };
-
- extern struct niotable nio_serial;
- extern struct niotable nio_stdio;
- extern struct niotable nio_dnet;
- extern struct niotable nio_rlogin;
- extern struct niotable nio_telnet;
-
- struct niotable *niotable =
- #if USE_RLOGIN
- &nio_rlogin;
- enum iotype iotype = rlogin;
- #elif USE_TELNET
- &nio_telnet;
- enum iotype iotype = telnet;
- #elif USE_SERIAL
- &nio_serial;
- enum iotype iotype = serial;
- #elif USE_DNET
- &nio_dnet;
- enum iotype iotype = dnet;
- #elif USE_STDIO
- &nio_stdio;
- enum iotype iotype = stdio;
- #else
- #error No IO method defined
- #endif
-
- /*
- * Initialize nioinit structure
- */
- void
- ninit(enum iotype iotype)
- {
- switch (iotype) {
- #if USE_SERIAL
- case serial:
- niotable = &nio_serial;
- return;
- #endif
- #if USE_STDIO
- case stdio:
- niotable = &nio_stdio;
- return;
- #endif
- #if USE_DNET
- case dnet:
- niotable = &nio_dnet;
- return;
- #endif
- #if USE_RLOGIN
- case rlogin:
- niotable = &nio_rlogin;
- return;
- #endif
- #if USE_TELNET
- case telnet:
- niotable = &nio_telnet;
- return;
- #endif
- default:
- fatalError("no support for %s in this version",
- iotype == serial ? "serial devices" :
- (iotype == stdio ? "AmigaDOS IO" :
- (iotype == dnet ? "dnet" :
- (iotype == telnet ? "telnet" : "rlogin"))));
- }
- }
-
- /*
- * Virtual functions
- */
- long nopen(char **hostvector)
- {
- return (*niotable->nopen)(hostvector);
- }
-
- long nnread(char *buf, long length)
- {
- return (*niotable->nnread)(buf, length);
- }
-
- long nwrite(char *buf, long length)
- {
- return (*niotable->nwrite)(buf, length);
- }
-
- void niosize(ushort s, ushort t, ushort u, ushort v)
- {
- (*niotable->niosize)(s, t, u, v);
- }
-
- void nioctl(int code, int arg1, int arg2)
- {
- (*niotable->nioctl)(code, arg1, arg2);
- }
-
- int nabort(void)
- {
- return (*niotable->nabort)();
- }
-
- void nclose(void)
- {
- (*niotable->nclose)();
- }
-
- #if USE_SERIAL
- /*
- * Define serial IO routines
- */
-
- #include <devices/serial.h>
-
- static int serial_is_open = 0;
- static int aborted = 0;
- static struct IOExtSer *inreq = NULL, *outreq = NULL;
-
- /*
- * Open a nio channel
- */
- long nopen_serial(char **hv)
- {
- if (!(iop = CreateMsgPort()) ||
- !(inreq = (struct IOExtSer *)CreateIORequest(iop, sizeof(*inreq))) ||
- !(outreq = (struct IOExtSer *)CreateIORequest(iop, sizeof(*outreq))) ||
- (inreq->io_SerFlags |= SERF_RAD_BOOGIE|(np.shared ? SERF_SHARED : 0),
- OpenDevice(np.device, np.unit, (struct IORequest *)inreq, 0))) {
- fatalError("Unable to open %s unit %ld.", np.device, itos(np.unit));
- }
-
- serial_is_open = 1;
-
- /* Set speed */
- inreq->io_Baud = np.bps;
- inreq->IOSer.io_Command = SDCMD_SETPARAMS;
- DoIO(inreq);
-
- *(outreq) = *(inreq);
- inreq->IOSer.io_Command = CMD_READ;
- inreq->IOSer.io_Data = (APTR)inbuf;
- inreq->IOSer.io_Length = (ULONG)1;
- /* inreq->IOSer.io_Flags = IOB_QUICK; */
- SendIO((struct IORequest *)inreq);
-
- return 1 << iop->mp_SigBit;
- }
-
- /*
- * Read characters from line
- */
- long nnread_serial(char *buf, long length)
- {
- long ret, save;
-
- if (GetMsg(iop)) {
- buf[0] = inbuf[0] & 127;
- inreq->IOSer.io_Command = SDCMD_QUERY;
- DoIO((struct IORequest *)inreq);
- save = inreq->IOSer.io_Actual;
- if (ret = MIN(inreq->IOSer.io_Actual, length)) {
- inreq->IOSer.io_Command = CMD_READ;
- inreq->IOSer.io_Data = (APTR)(buf+1);
- inreq->IOSer.io_Length = (ULONG)ret;
- DoIO((struct IORequest *)inreq);
-
- if (inreq->IOSer.io_Error) {
- if (inreq->IOSer.io_Error == 12)
- termout("\n**** Serial Buffer Overflow; CLEARING BUFFERS\n", 50);
- else
- termout("**** Serial Device Error; CLEARING BUFFERS\n", 43);
- inreq->IOSer.io_Command = CMD_CLEAR;
- DoIO((struct IORequest *)inreq);
- }
-
- ret = inreq->IOSer.io_Actual;
- }
- inreq->IOSer.io_Command = CMD_READ;
- inreq->IOSer.io_Data = (APTR)inbuf;
- inreq->IOSer.io_Length = (ULONG)1;
- SendIO((struct IORequest *)inreq);
- return ret + 1;
- }
- else
- return 0;
- }
-
- long
- nwrite_serial(char *buf, long length)
- {
- if (!aborted) {
- outreq->IOSer.io_Command = CMD_WRITE;
- outreq->IOSer.io_Data = (APTR)buf;
- outreq->IOSer.io_Length = (ULONG)length;
- DoIO((struct IORequest *)outreq);
- return (long)outreq->IOSer.io_Actual;
- } else {
- return length;
- }
- }
-
- void nioctl_serial(int code, int arg1, int arg2)
- {
- if (aborted)
- return;
-
- if (code == NIO_FLUSH) {
- outreq->IOSer.io_Command = CMD_CLEAR;
- DoIO((struct IORequest *)outreq);
- }
- else if (code == NIO_BREAK) {
- outreq->IOSer.io_Command = SDCMD_BREAK;
- DoIO((struct IORequest *)outreq);
- }
- }
-
- /*
- * Toggle unlisten mode.
- * No serial activity may occur until another nabort()
- */
- int nabort_serial(void)
- {
- if (aborted = !aborted) {
- if (!CheckIO((struct IORequest *)inreq)) {
- AbortIO((struct IORequest *)inreq);
- WaitIO((struct IORequest *)inreq);
- }
- } else {
- /* We know that the inreq is aborted */
- inreq->IOSer.io_Command = CMD_READ;
- inreq->IOSer.io_Data = (APTR)inbuf;
- inreq->IOSer.io_Length = (ULONG)1;
- inreq->IOSer.io_Flags = IOB_QUICK;
- SendIO((struct IORequest *)inreq);
- }
-
- return aborted;
- }
-
- void nclose_serial(void)
- {
- if (inreq) {
- if (serial_is_open) {
- if (!CheckIO((struct IORequest *)inreq)) {
- AbortIO((struct IORequest *)inreq);
- WaitIO((struct IORequest *)inreq);
- }
- CloseDevice((struct IORequest *)inreq);
- }
- DeleteIORequest((struct IORequest *)inreq);
- }
- if (outreq) {
- DeleteIORequest(outreq);
- }
- if (iop) {
- DeleteMsgPort(iop);
- }
- }
-
- #define niosize_serial niosize_generic
-
- struct niotable nio_serial = {
- nopen_serial, nnread_serial, nwrite_serial,
- niosize_serial, nioctl_serial, nclose_serial,
- nabort_serial,
- };
- #endif /* USE_SERIAL */
-
- #if USE_DNET
- /*
- * Define DNET IO routines
- */
-
- #include <local/typedefs.h>
- #define DeadKeyConvert do_not_use_DeadKeyConvert
- #include <local/suplib_protos.h>
- #undef DeadKeyConvert
- #include <dnet/channel.h>
- #include <lib/dnetlib.h>
- #include <server/servers.h>
-
- CHANN *io_chan = NULL;
-
- /*
- * Open a nio channel
- */
- long nopen_dnet(char **hv)
- {
- io_chan = (CHANN *)DOpen(NULL, PORT_IALPHATERM, 20, 15);
- if(!io_chan) {
- fatalError("unable to connect to DNet ALPHATERM port");
- }
- DQueue(io_chan, 32);
- return 1 << ((struct MsgPort *)io_chan)->mp_SigBit;
- }
-
- static void handleioctl(short cmd, short val, char aux)
- {
- static short saverows;
-
- if (iotype == dnet) {
- switch (cmd) {
- #if 0
- case CIO_MODE:
- Cooked = val;
- break;
- #endif
- case CIO_SETROWS:
- saverows = val;
- return;
- case CIO_SETCOLS:
- dssizewindow(saverows, val, 0);
- return;
- }
- }
- }
-
- long nnread_dnet(char *buf, long n)
- {
- n = DNRead(io_chan, buf, n);
-
- if (n == -2) {
- char aux;
- short val, cmd;
-
- cmd = DGetIoctl(io_chan, &val, &aux);
- if (cmd != -1) {
- handleioctl(cmd, val, aux);
- }
- return 0;
- } else
- return n;
- }
-
- long nwrite_dnet(char *buf, long length)
- {
- return DWrite(io_chan, buf, length);
- }
-
- /*
- * Inform the other end of connection about window size changes
- */
- void niosize_dnet(ushort ws_row, ushort ws_col,
- ushort ws_xpixel, ushort ws_ypixel)
- {
- DIoctl(io_chan, CIO_SETROWS, ws_row, 0);
- DIoctl(io_chan, CIO_SETCOLS, ws_col, 0);
- }
-
- /*
- * Send ioctl (flush, break &c)
- */
- void nioctl_dnet(int code, int arg1, int arg2)
- {
- DIoctl(io_chan, code, arg1, arg2);
- }
-
- void nclose_dnet(void)
- {
- if (io_chan)
- DClose(io_chan);
- }
-
- #define nabort_dnet nabort_generic
-
- struct niotable nio_dnet = {
- nopen_dnet, nnread_dnet, nwrite_dnet,
- niosize_dnet, nioctl_dnet, nclose_dnet,
- nabort_dnet,
- };
- #endif /* USE_DNET */
-
- #if USE_RLOGIN || USE_TELNET
- /*
- * Common parts for rlogin and telnet
- */
-
- #define BSDSOCKET_H
- #include <sys/param.h>
- #include <sys/socket.h>
- #include <sys/ioctl.h>
- #include <netinet/in.h>
- #include <netdb.h>
- #include <arpa/inet.h>
- #include <netinet/in_systm.h>
- #include <netinet/ip.h>
- #include <errno.h>
- #include <unistd.h>
- #include "rlogin.h"
- #define ioctl IoctlSocket
-
- /* Prototypes */
- #ifdef USE_PRAGMAS
- #include <proto/socket.h>
- #endif
- #ifdef USE_INLINE
- #include <inline/socket.h>
- #endif
- #ifdef USE_CLIB
- #include <clib/socket_protos.h>
- #endif
-
- struct Library *SocketBase = NULL;
-
- #ifdef USE_GETUID
- #ifdef USE_PRAGMAS
- #include <proto/usergroup.h>
- #elif USE_INLINE
- #include <inline/usergroup.h>
- #else
- #include <clib/usergroup_protos.h>
- #endif
- #include <pwd.h>
- struct Library *UserGroupBase = NULL;
- #endif
-
- /*
- * Chose a random member of the hostvector
- */
- const char *random_host(const char **hostvector)
- {
- static union {
- struct timeval time;
- UBYTE bytes[8];
- } seed;
- const char *host;
- int rnd, hosts;
-
- for (hosts = 0; hostvector[hosts]; hosts++)
- ;
-
- if (hosts == 0)
- return NULL;
-
- GetSysTime(&seed.time);
-
- rnd = (seed.bytes[0] + seed.bytes[1] + seed.bytes[2] + seed.bytes[3] +
- seed.bytes[4] + seed.bytes[5] + seed.bytes[6] + seed.bytes[7])
- % hosts;
-
-
- host = hostvector[rnd];
-
- /* Remove chosen member */
- hostvector[rnd] = hostvector[hosts - 1];
- hostvector[hosts - 1] = NULL;
-
- return host;
- }
-
- const char termnames[3][6] = { "vt102", "vt52", "h19" };
-
- /* Common global variables */
- int rsock = -1;
-
- BYTE IO_bit = -1;
- BYTE URG_bit = -1;
- ULONG SIGURG = 0;
-
- /* Is it OK to send window size reports */
- char okwinch = 0;
- /* Current window size */
- struct winsize_packet winsize = { 0 };
-
- #endif
-
- #if USE_RLOGIN
-
- /*
- * Open a nio channel
- */
- long nopen_rlogin(char **hostvector)
- {
- long iomask;
- int true = 1;
- struct servent *sp;
- char *user, *remote;
- char term[32];
- const char *host;
-
- SocketBase = OpenLibrary("bsdsocket.library", 3L);
- if (!SocketBase) {
- fatalError("unable to open BSD socket library");
- }
-
- SetErrnoPtr(&errno, sizeof(errno));
-
- IO_bit = AllocSignal(-1);
- URG_bit = AllocSignal(-1);
-
- iomask = 1 << IO_bit;
- SIGURG = 1 << URG_bit;
-
- SetSocketSignals(SIGBREAKF_CTRL_C, iomask, SIGURG|iomask);
-
- sp = getservbyname("login", "tcp");
- if (sp == NULL) {
- fatalError("login/tcp: unknown service");
- }
-
- /* Local username */
- #ifdef USE_GETUID
- if (UserGroupBase = OpenLibrary(USERGROUPNAME, 2))
- {
- struct passwd *pw = getpwuid(getuid());
- if (pw)
- user = pw->pw_name;
- else
- user = "nobody";
- }
- else
- #endif
- {
- user = getenv("USER");
- if (!user) user = "nobody";
- }
-
- /* Our username in remote system */
- remote = np.remotename ? np.remotename : user;
-
- /* terminal type is catenated with "/" and line speed */
- strcpy(term, np.remoteterm ? np.remoteterm : termnames[np.emulation]);
- strncat(term, "/", sizeof(term));
- strncat(term, itos(np.bps), sizeof(term));
-
- /* Get the host name to use */
- host = random_host(hostvector);
- if (host == NULL) {
- fatalError("no host specified.");
- }
-
- /* Open remote login session */
- rsock = rcmd(&host, sp->s_port, user, remote, term, NULL);
- if (rsock < 0) {
- fatalError("rmcd(): %s", strerror(errno));
- }
-
- /* Set title to remote host name */
- /* (This has no effect if title is explicitly set) */
- if (!np.title) {
- np.title = (char *)host;
- setnewtitle();
- }
-
- /* Set Signal driven IO */
- #if USE_FIONBIO
- ioctl(rsock, FIONBIO, (char*)&true);
- #endif
- ioctl(rsock, FIOASYNC, (char*)&true);
- true = IPTOS_LOWDELAY;
- (void)setsockopt(rsock, IPPROTO_IP, IP_TOS, (char *)&true, sizeof(int));
-
- #ifdef USE_GETUID
- /*
- * We don't need this any more
- */
- if (UserGroupBase) {
- CloseLibrary(UserGroupBase);
- UserGroupBase = NULL;
- }
- #endif
-
- return iomask;
- }
-
- static int rread(long s, char *buf, int length);
-
- /*
- * Read from socket
- */
- long nnread_rlogin(char *buf, long length)
- {
- long n = 0, m;
-
- if (SetSignal(0L, SIGURG) & SIGURG) {
- n = rread(rsock, buf, length);
- if (n >= 0)
- SetSignal(1 << IO_bit, 1 << IO_bit);
- return n;
- }
-
- for (;;) {
- #if USE_FIONBIO
- m = recv(rsock, buf + n, length - n, 0);
- if (m < 0) {
- if (errno == EWOULDBLOCK) {
- return n;
- } else {
- return m;
- }
- } else if (m == 0) {
- /* This may be caused by the remote socket shutdown
- * or OOB data delivered to the socket.
- */
- ioctl(rsock, SIOCATMARK, (caddr_t)&m);
- if (m) {
- SetSignal(SIGURG, SIGURG);
- }
- return n;
- }
- n += m;
- #else
- /* Find out how many bytes there are waiting for us */
- if (ioctl(rsock, FIONREAD, (char*)&m) < 0) {
- perror("nnread FIONREAD");
- return -1;
- }
- if (n + m > length) {
- SetSignal(1 << IO_bit, 1 << IO_bit);
- m = length - n;
- }
- if (m == 0)
- return n;
- m = recv(rsock, buf + n, m, 0);
- if (m > 0) {
- n += m;
- } else {
- if (errno == EWOULDBLOCK)
- return n;
- else
- return m; /* error */
- }
- #endif
- }
- }
-
- long nwrite_rlogin(char *buf, long length)
- {
- return send(rsock, buf, length, 0);
- }
-
- /*
- * Inform the other end of connection about window size changes
- */
- void niosize_rlogin(ushort ws_row, ushort ws_col,
- ushort ws_xpixel, ushort ws_ypixel)
- {
- winsize.title[0] = winsize.title[1] = 0377;
- winsize.title[2] = winsize.title[3] = 's';
- winsize.ws_row = htons(ws_row);
- winsize.ws_col = htons(ws_col);
- winsize.ws_xpixel = htons(ws_xpixel);
- winsize.ws_ypixel = htons(ws_ypixel);
-
- if (okwinch) {
- send(rsock, (char *)&winsize, sizeof(winsize), 0);
- }
- }
-
- void nclose_rlogin(void)
- {
- if (rsock != -1)
- CloseSocket(rsock), rsock = -1;
- if (IO_bit != -1)
- FreeSignal(IO_bit), IO_bit = -1;
- if (URG_bit != -1)
- FreeSignal(URG_bit), URG_bit = -1;
- if (SocketBase)
- CloseLibrary(SocketBase), SocketBase = NULL;
- #ifdef USE_GETUID
- if (UserGroupBase)
- CloseLibrary(UserGroupBase), UserGroupBase = NULL;
- #endif
- }
-
- /*
- * Read next OOB data
- */
- static int rread(long s, char *buf, int length)
- {
- char tiop;
- int n = 0, m;
- int wasting = 0;
-
- for (;;) {
- /* We are at OOB data? */
- ioctl(s, SIOCATMARK, (caddr_t)&m);
- if (m) {
- m = recv(s, &tiop, 1, MSG_OOB);
- if (m < 0) break;
-
- if (tiop & TIOCPKT_WINDOW) {
- /* Let server know about window size changes */
- okwinch = 1;
- if (winsize.title[0])
- send(rsock, (char *)&winsize, sizeof(winsize), 0);
- }
- /* Here we might want to handle other bits */
- if (tiop & TIOCPKT_FLUSHWRITE) {
- for (;;) {
- if (ioctl(s, SIOCATMARK, (caddr_t)&m) < 0) {
- (void)perror(PROGNAME ": ioctl");
- n = -1;
- break;
- }
- if (m) break;
- n = recv(s, inbuf, sizeof (inbuf), 0);
- if (n <= 0) break;
- }
- n = 0;
- }
-
- #if USE_FIONBIO
- /* SIGIO may not be sent for the rest of buffered data */
- if (length > 0) {
- m = recv(s, buf, length, 0);
- if (m >= 0) {
- n += m;
- return n;
- } else if (errno == EWOULDBLOCK) {
- return n;
- } else {
- return -1;
- }
- }
- #else
- /* There is a bug in socket code that jams without this.. */
- recv(s, inbuf, 0, 0);
- #endif
- return n;
- }
- if ((m = recv(s, buf, length, 0)) < 0)
- break;
- if (wasting)
- continue;
- n += m; buf +=m; length -= m;
- if (length > 0) continue;
- wasting = 1; buf = inbuf; length = sizeof(inbuf);
- }
-
- return n;
- }
-
- #define nioctl_rlogin nioctl_generic
- #define nabort_rlogin nabort_generic
-
- struct niotable nio_rlogin = {
- nopen_rlogin, nnread_rlogin, nwrite_rlogin,
- niosize_rlogin, nioctl_rlogin, nclose_rlogin,
- nabort_rlogin,
- };
- #endif /* USE_RLOGIN */
-
- #if USE_STDIO
- /*
- * DOS IO routines
- */
-
- struct FileHandle *io_fh;
- struct StandardPacket *inpkt = NULL;
-
- /*
- * Initialize DOS packet with standard args
- */
- static void initpkt(LONG action, ULONG arg1, ULONG arg2)
- {
- inpkt->sp_Msg.mn_Node.ln_Name = (char *)&(inpkt->sp_Pkt);
- inpkt->sp_Pkt.dp_Link = &inpkt->sp_Msg;
- inpkt->sp_Pkt.dp_Port = iop;
- inpkt->sp_Pkt.dp_Type = action;
- inpkt->sp_Pkt.dp_Arg1 = io_fh->fh_Arg1;
- inpkt->sp_Pkt.dp_Arg2 = arg1;
- inpkt->sp_Pkt.dp_Arg3 = arg2;
- }
-
- /*
- * Open a nio channel
- */
- long nopen_stdio(char **hv)
- {
- struct Process *me = (struct Process *)FindTask(0L);
- io_fh = (struct FileHandle *)BADDR(me->pr_CIS);
-
- iop = CreateMsgPort();
- if (iop)
- inpkt = (struct StandardPacket *)CreateIORequest(iop, sizeof(*inpkt));
-
- if (!iop || !inpkt) {
- fatalError("trouble opening stdin");
- }
-
- initpkt(ACTION_WAIT_CHAR, 1000000L, 0);
- PutMsg(io_fh->fh_Type, (struct Message *)inpkt);
-
- return 1 << iop->mp_SigBit;
- }
-
- long nnread_stdio(char *buf, long length)
- {
- long ret = 0;
-
- GetMsg(iop);
-
- if (inpkt->sp_Pkt.dp_Res1) {
- initpkt(ACTION_READ, (ULONG)inbuf, sizeof(inbuf));
- PutMsg(io_fh->fh_Type, (struct Message *)inpkt);
- Wait(1 << iop->mp_SigBit);
- GetMsg(iop);
-
- ret = inpkt->sp_Pkt.dp_Res1;
- if (ret != 0) {
- CopyMem(inbuf, buf, ret);
- } else {
- ret = -1;
- }
- }
-
- initpkt(ACTION_WAIT_CHAR, 1000000L, 0);
- PutMsg(io_fh->fh_Type, (struct Message *)inpkt);
- return ret;
- }
-
- long nwrite_stdio(char *buf, long length)
- {
- return Write(Output(), buf, length);
- }
-
- void nclose_stdio(void)
- {
- if (inpkt) {
- /* Should we wait for reply? */
- WaitPort(iop);
- DeleteIORequest(inpkt);
- inpkt = NULL;
- }
- if (iop) {
- DeleteMsgPort(iop);
- iop = NULL;
- }
- }
-
- #define niosize_stdio niosize_generic
- #define nioctl_stdio nioctl_generic
- #define nabort_stdio nabort_generic
-
- struct niotable nio_stdio = {
- nopen_stdio, nnread_stdio, nwrite_stdio,
- niosize_stdio, nioctl_stdio, nclose_stdio,
- nabort_stdio,
- };
- #endif /* USE_STDIO */
-
- #if USE_TELNET
-
- #include <arpa/telnet.h>
- #include "telnet.h"
-
- /*
- * Open a nio channel to telnet
- */
- long nopen_telnet(char **hostvector)
- {
- long iomask;
- struct servent *sp;
- long port;
- const char *host;
-
- SocketBase = OpenLibrary("bsdsocket.library", 3L);
- if (!SocketBase) {
- fatalError("unable to open BSD socket library");
- }
-
- SetErrnoPtr(&errno, sizeof errno);
-
- IO_bit = AllocSignal(-1);
- URG_bit = AllocSignal(-1);
-
- iomask = 1 << IO_bit;
- SIGURG = 1 << URG_bit;
-
- SetSocketSignals(SIGBREAKF_CTRL_C, iomask, SIGURG|iomask);
-
- sp = getservbyname(np.service, "tcp");
- if (sp == NULL && StrToLong(np.service, &port) <= 0) {
- fatalError("%s/tcp: unknown service", np.service);
- }
-
- /* Get the host name to use */
- host = random_host(hostvector);
- if (host == NULL) {
- fatalError("no host specified.");
- }
-
- /* open telnet session */
- if ((rsock = socket(AF_INET, SOCK_STREAM, 0)) != -1) {
- struct sockaddr_in addr = { 0 };
- struct hostent * h;
- int true = 1;
- long pid = (long)getpid();
-
- /* Set Signal driven IO */
- ioctl(rsock, FIOSETOWN, (caddr_t)&pid);
- ioctl(rsock, FIOASYNC, (char*)&true);
- setsockopt(rsock, SOL_SOCKET, SO_OOBINLINE, (char *)&true, sizeof(true));
- true = IPTOS_LOWDELAY;
- setsockopt(rsock, IPPROTO_IP, IP_TOS, (char *)&true, sizeof(true));
-
- addr.sin_family = AF_INET;
- if (sp != NULL)
- addr.sin_port = sp->s_port;
- else
- addr.sin_port = port;
-
- if ((h = gethostbyname(host)) == NULL)
- fatalError("gethostbyname: %s\n", "no such beast"); /*XXX*/
-
- bcopy(h->h_addr, &addr.sin_addr.s_addr, sizeof (struct in_addr));
-
- if (connect(rsock, (struct sockaddr *)&addr, sizeof addr) == -1)
- fatalError("connect: %s\n", strerror(errno));
- } else {
- fatalError("socket: %s\n", strerror(errno));
- }
-
- /* Set title to remote host name */
- /* (This has no effect if title is explicitly set) */
- if (!np.title) {
- np.title = (char *)host;
- setnewtitle();
- }
-
- return iomask;
- }
-
- /*
- * Read from socket
- */
- long nnread_telnet(char *buf, long length)
- {
- long n = 0, m;
-
- #if 0 /*XXX*/
- if (SetSignal(0L, SIGURG) & SIGURG) {
- /* Handle urgent data (SYNC) */
-
- }
- #endif
-
- for (;;) {
- /* Find out how many bytes there are waiting for us */
- if (ioctl(rsock, FIONREAD, (char*)&m) < 0) {
- perror("nnread FIONREAD");
- return -1;
- }
-
- /* If there is too much data for our buffer... */
- if (n + m > length) {
- /* ... continue, set signal for us */
- SetSignal(1 << IO_bit, 1 << IO_bit);
- m = length - n;
- }
-
- /* No more data, call telnet protocol machine and return */
- if (m == 0) {
- return telnetdo(buf, n);
- }
-
- m = recv(rsock, buf + n, m, 0);
-
- if (m != -1) {
- n += m;
- } else {
- if (errno == EWOULDBLOCK)
- /* Call telnet protocol machine and return */
- return telnetdo(buf, n);
- else
- return -1; /* error */
- }
- }
- }
-
- /*
- * Write the buffer into telnet
- */
- long nwrite_telnet(char *buf, long length)
- {
- long i;
-
- for (i = 0; i < length; i++) {
- register char c = buf[i];
-
- /* We are supposed to quote these */
- if (c == 0xff || c == 0x0d) {
- /*
- * We must quote the buffer
- */
- char telnet_buffer[TELNETBUFFERSIZE];
- long count;
-
- /*
- * If there is a lot of stuff to send, do it without copying
- */
- if (i >= TELNETBUFFERSIZE / 2) {
- if (send(rsock, buf, i, 0) == -1)
- return -1;
- count = 0;
- } else {
- memcpy(telnet_buffer, buf, count = i);
- }
-
- /*
- * Quote and copy
- */
- for (; i < length; i++) {
- switch (c = buf[i]) {
- case 0xff:
- telnet_buffer[count++] = c;
- break;
- case 0x0d:
- telnet_buffer[count++] = c;
- c = '\0';
- break;
- }
-
- telnet_buffer[count++] = c;
-
- /* If our quoting buffer overflows, send it */
- if (count >= TELNETBUFFERSIZE - 1) {
- if (send(rsock, telnet_buffer, count, 0) == -1)
- return -1;
- count = 0;
- }
- }
-
- /* Send the quoted buffer */
- if (count > 0 && send(rsock, telnet_buffer, count, 0) == -1)
- return -1;
-
- return length;
- }
- }
-
- /* There was no characters to quote, send as it is */
- return send(rsock, buf, length, 0);
- }
-
- /*
- * Current window size
- */
- static ushort ws_row_stored, ws_col_stored;
-
- /*
- * Do IAC SB NAWS
- */
- extern void do_naws(void)
- {
- u_char buf[3 + 4 + 4 + 2], *p = buf;
-
- *p++ = IAC;
- *p++ = SB;
- *p++ = TELOPT_NAWS;
-
- /* We must quote IACs */
- if ((ws_col_stored >> 8) == IAC) {
- *p++ = IAC;
- }
- *p++ = ws_col_stored >> 8;
- if ((ws_col_stored & 0xff) == IAC) {
- *p++ = IAC;
- }
- *p++ = ws_col_stored & 0xff;
-
- if ((ws_row_stored >> 8) == IAC) {
- *p++ = IAC;
- }
- *p++ = ws_row_stored >> 8;
- if ((ws_row_stored & 0xff) == IAC) {
- *p++ = IAC;
- }
- *p++ = ws_row_stored & 0xff;
-
- *p++ = IAC;
- *p++ = SE;
-
- send(rsock, buf, p - buf, 0);
- }
-
- /*
- * Inform the other end of connection about window size changes
- */
- void niosize_telnet(ushort ws_row, ushort ws_col,
- ushort ws_xpixel, ushort ws_ypixel)
- {
- /* Store winsize so we can send NAWS after IAC DO NAWS */
- ws_row_stored = ws_row;
- ws_col_stored = ws_col;
-
- /* Do we have received IAC DO NAWS ? */
- if (okwinch) {
- do_naws();
- }
- }
-
- void nclose_telnet(void)
- {
- if (rsock != -1)
- CloseSocket(rsock), rsock = -1;
- if (IO_bit != -1)
- FreeSignal(IO_bit), IO_bit = -1;
- if (URG_bit != -1)
- FreeSignal(URG_bit), URG_bit = -1;
- if (SocketBase)
- CloseLibrary(SocketBase), SocketBase = NULL;
- }
-
- #define nioctl_telnet nioctl_generic
- #define nabort_telnet nabort_generic
-
- struct niotable nio_telnet = {
- nopen_telnet, nnread_telnet, nwrite_telnet,
- niosize_telnet, nioctl_telnet, nclose_telnet,
- nabort_telnet,
- };
-
- #endif /* USE_TELNET */
-